import FYGlobalVarMgr from '../../Global/FYGlobalVarMgr';
import { ArrayRemove } from '../../Util/ArrayUtil';
import FYUtility from '../../Util/FYUtility';
import FYMessenger from '../FYMessenger';
import FYResMgr from '../Res/FYResMgr';
import FYBaseUI from './FYBaseUI';
import FYBaseUIPanel from './FYBaseUIPanel';
import { EnumUITween } from './UIEnum';

const { ccclass, property } = cc._decorator;
/**
 * UI管理器
 */
@ccclass
export default class FYUIMgr {
    public static readonly Instance: FYUIMgr = new FYUIMgr();
    private constructor() { }

    //--------------------------------------------------------------------------------
    //#region ------------------------ 同步加载资源模式 ------------------------
    //--------------------------------------------------------------------------------

    /** UI对象父节点 */
    private _root: cc.Node;
    /** 已打开的UI的对象队列   注：用array不用map的原因，主要原因是map是无序的集合 */
    private openedUIArray: Array<FYBaseUI> = new Array<FYBaseUI>();
    /** 正在打开的UI的名称队列 */
    private openingUITagArray: Array<string> = new Array<string>();

    /**
     * 初始化
     * @param root UI对象父节点
     */
    public Init(root: cc.Node) {
        this._root = root;
    }

    /**
     * 打开UI
     * @param UIClass 界面类
     * @param param 参数
     */
    public async OpenUI(UIClass: { new(): FYBaseUI }, ...param): Promise<FYBaseUI> {
        return new Promise(async (resolve, reject) => {
            let targetName = new UIClass().PrefabName;
            if (FYUtility.IsNullOrEmpty(targetName)) {
                console.error('Open UI -> UI Name is null! ');
                reject(new Error('Open UI -> UI Name is null! '));
            }

            // 已打开的情况下
            let target = this.openedUIArray.find(item => item.PrefabName == targetName);
            if (target != null) {
                this.printOpenedUIList('Open UI -> UI Name is opened! name:' + targetName);
                ArrayRemove(this.openedUIArray, target);  //移除

                this.openedUIArray.push(target);          //放队尾
                this.SortOrder();                   //显示在最上层
                resolve(target);
            }

            //正在打开的情况下
            let isOnOpen = this.openingUITagArray.find(item => item == targetName)
            if (isOnOpen) {
                console.warn('Open UI -> but UI is OnOpen, name:' + targetName);
                reject(new Error('Open UI -> but UI is OnOpen, name:' + targetName));
            }

            //未打开的情况
            this.openingUITagArray.push(targetName);
            this.PrintOnOpenUIList('Open UI -> before Open UI with name:' + targetName);

            //从正在打开的UI List中移除
            let RemoveFromOnOpen = () => {
                let isOnOpen = this.openingUITagArray.find(item => item == targetName);
                if (isOnOpen) {
                    // console.trace("remove target Name from OnOpen List!");
                    ArrayRemove(this.openingUITagArray, targetName);
                } else {
                    console.error("can not find onOpen UI name, targetName:" + targetName);
                }
                this.PrintOnOpenUIList('Open UI -> After Open UI with name:' + targetName);
            }

            let prefab: cc.Prefab = await FYResMgr.Instance.LoadRes(targetName, cc.Prefab).catch((reason) => {
                RemoveFromOnOpen()
                console.error('UIManager >> GetInstance >> node is null!, name:' + targetName + ",err" + JSON.stringify(reason));
                reject(new Error('UIManager >> GetInstance >> node is null!, name:' + targetName + ",err" + JSON.stringify(reason)));
            });
            let node = cc.instantiate(prefab);
            let targetUI = node.addComponent(UIClass);
            targetUI.Init(param);
            // 有了父对象 onLoad和onEnable会立刻被执行
            this._root.addChild(node);
            node.setPosition(0, 0)
            //从onOpen UI List 中移除该已打开的UI
            RemoveFromOnOpen();
            //在已打开的UI List 中添加该UI
            this.openedUIArray.push(targetUI);
            //调整UI层级
            this.SortOrder();
            //打印层级
            this.printOpenedUIList('After Open UI >>' + targetName);

            if (targetUI.ShowTweenType != EnumUITween.None) {
                await targetUI.PlayShowTween();
                resolve(targetUI);
            } else {
                resolve(targetUI);
            }

        });
    }


    /**
     * 关闭单个UI
     * @param UIClass 界面类
     */
    public async CloseUI(UIClass: { new(): FYBaseUI }): Promise<void> {
        return new Promise(async (resolve, reject) => {
            let targetName = new UIClass().PrefabName;
            console.log('Close UI  -> UIName=' + targetName);
            let targetUI: FYBaseUI = this.openedUIArray.find(item => item.PrefabName == targetName);
            if (targetUI == null) {
                console.warn('CloseUI -> target UI is null,name:' + targetName);
                reject(new Error('CloseUI -> target UI is null,name:' + targetName));
            }

            if (targetUI.HideTweenType != EnumUITween.None) {
                await targetUI.PlayHideTween();
                targetUI.node.destroy();
                ArrayRemove(this.openedUIArray, targetUI);
                this.printOpenedUIList('After Close UI :' + targetName);
                resolve();
            } else {
                targetUI.node.destroy();
                ArrayRemove(this.openedUIArray, targetUI);
                this.printOpenedUIList('After Close UI :' + targetName);
                resolve();
            }
        });
    }



    /**
     * 一次关闭所有UI
     */
    public CloseAll() {
        for (let index = 0; index < this.openedUIArray.length; index++) {
            const ui = this.openedUIArray[index];
            ui.node.destroy()
        }
        this.openedUIArray = new Array<FYBaseUI>();
        this.printOpenedUIList('After Close All UI');
    }

    /**
     * 调整UI层级
     */
    private SortOrder() {
        for (let index = 0; index < this.openedUIArray.length; index++) {
            let targetUI: FYBaseUI = this.openedUIArray[index]
            targetUI.node.zIndex = targetUI.HierarchyType + index * 2;
        }
    }

    /**
     * 打印已打开的UI队列
     * @param desc 
     */
    private printOpenedUIList(desc: string = null) {
        if (this.openedUIArray.length <= 0) {
            console.log(desc + '>>> Now Opened UI List is Empty')
            return;
        }

        let str = ''
        for (let index = 0; index < this.openedUIArray.length; index++) {
            const ui = this.openedUIArray[index];
            str = str + '\n[ name: ' + ui.PrefabName + ', zIndex: ' + ui.node.zIndex + ' ]'
        }
        console.log(desc + '>>> Now  Opened UI List :' + str)
    }

    /**
     * 打印正在打开的UI队列
     * @param desc 
     */
    private PrintOnOpenUIList(desc: string = null) {
        if (this.openingUITagArray.length <= 0) {
            console.log(desc + '>>> Now OnOpen UI List is Empty')
            return;
        }

        let str = ''
        for (let index = 0; index < this.openingUITagArray.length; index++) {
            const name = this.openingUITagArray[index];
            str = str + '\n[ name: ' + name + ' ]'
        }
        console.log(desc + '>>> Now OnOpen UI List :' + str)
    }

    //#endregion

    //--------------------------------------------------------------------------------
    //#region ------------------------ 先加载所有资源再使用模式 ------------------------
    //--------------------------------------------------------------------------------

    /** 正在加载UI预制 */
    public static readonly MsgPreLoadUIProgress = "PreLoadUIProgress";
    /** 图集加载完毕 */
    public static readonly MsgPreLoadUIComplete = "PreLoadUIComplete";

    /** UI预制字典 */
    private _dictUIPrefab = {};
    /** UI界面字典 */
    private _dictUIPanel: { [key: string]: FYBaseUIPanel } = {};

    /**
     * 预加载UI预制 路径是resources/prefabs/UI
     */
    public preLoad() {
        let self = this;
        cc.loader.loadResDir("prefabs/UI", cc.Prefab, function (completedCount, totalCount, item) {
            FYMessenger.Instance.send(FYUIMgr.MsgPreLoadUIProgress, completedCount, totalCount)
        },
            function (err, assets) {
                for (let i = 0; i < assets.length; i++) {
                    self._dictUIPrefab[assets[i]._name] = assets[i].data;
                }
                FYMessenger.Instance.send(FYUIMgr.MsgPreLoadUIComplete);
            });
    }

    /**
     * 显示界面
     * @param uiName 界面名字
     * @param parent 父对象
     * @param param 参数
     */
    public show(uiName, parent = FYGlobalVarMgr.Instance.NodeTop, ...param) {
        if (!parent) {
            parent = FYGlobalVarMgr.Instance.NodeTop;
        }
        if (!this._dictUIPrefab[uiName]) {
            cc.error(uiName + " is not prelaod");
            return;
        }

        if (this._dictUIPanel[uiName]) {
            this._dictUIPanel[uiName].setActive(true);
        } else {
            this._dictUIPanel[uiName] = FYUtility.addChild(parent, this._dictUIPrefab[uiName]).getComponent(FYBaseUIPanel);
        }
        this._dictUIPanel[uiName].node.setSiblingIndex(this._dictUIPanel[uiName].node.parent.childrenCount);
        FYMessenger.Instance.send(uiName, param);
    }

    /**
     * 隐藏界面
     * @param uiName 界面名字
     */
    public hide(uiName) {
        if (this._dictUIPanel[uiName]) {
            this._dictUIPanel[uiName].setActive(false);
        }
    }

    /**
     * 关闭界面
     * @param uiName 界面名字
     */
    public close(uiName) {
        if (this._dictUIPanel[uiName]) {
            this._dictUIPanel[uiName].node.destroy();
            delete this._dictUIPanel[uiName];
        }
    }

    //#endregion
}
